/////////////////////////////////////////////////////
// Filename: CMemoryManager.h
//
// Author: Gant Briseno
// Last Edited: 6/30/2011
//
// Purpose: To handle internal memory management and
//			to make sure there is minimal calls to
//			new/malloc and delete/free
/////////////////////////////////////////////////////
#ifndef MEMORY_MANAGER_H
#define MEMORY_MANAGER_H

class CMemoryManager
{
public:
	struct Header
	{
		// How much memory is free INSIDE the block : excludes header and footer size
		// High order bit of 1 == used memory block
		// High order bit of 0 == free memory block
		unsigned int size;
		// Pointer to the previous free header in the Cyclic Doubly Linked List
		Header* prev;
		// Pointer to the next free header in the Cyclic Doubly Linked List
		Header* next;
	};
	struct Footer
	{
		// How much memory is free INSIDE the block : excludes header and footer size
		// High order bit of 1 == used memory block
		// High order bit of 0 == free memory block
		unsigned int size;
	};

private:
	// Singleton
	static CMemoryManager* mInstance;

	// Disabled for Singleton use
	CMemoryManager();
	CMemoryManager(const CMemoryManager &);
	CMemoryManager & operator=(const CMemoryManager &);

	// Entire Memory Pool
	char* mPool;

	// The Last footer
	Footer* mEndPoolFooter;

	// The Entry Point to the free list (Cyclic Doubly-Linked List)
	Header* mFreeHead;

	// How much memory was allocated for this pool.
	unsigned int mTotalPoolSize;

	// Function pointer for the allocation behavior
	Header*(CMemoryManager::*FindFreeMemory)(unsigned int allocSize);

	//////////////////////////////////////////////////////////////////
	// Name: FirstAvailable
	//
	// Purpose: To find the first chunk of free memory is big enough
	//			for the object that wants to be allocated
	//
	// In:
	//		allocSize - The amount, in bytes, of memory that has
	//					been requested
	//
	// Out:
	//		A Header pointer pointing to the header of the chunk
	//		of free memory to se
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	Header* FirstAvailable(unsigned int allocSize);
	
public:
	//////////////////////////////////////////////////////////////////
	// Name: Destructor
	//
	// Purpose: To clean up any dynamic memory
	//
	// In:
	//		none
	//
	// Out:
	//		none
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	~CMemoryManager();

	//////////////////////////////////////////////////////////////////
	// Name: GetInstance
	//
	// Purpose: Returns the single instance of this object, and
	//			creates that instance if one is not readily available
	//
	// In:
	//		none
	//
	// Out:
	//		A pointer pointing to the only instance of this object
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	static CMemoryManager* GetInstance();

	//////////////////////////////////////////////////////////////////
	// Name: DeleteInstance
	//
	// Purpose: To delete the instance if it has already been created
	//
	// In:
	//		none
	//
	// Out:
	//		none
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	static void DeleteInstance();

	//////////////////////////////////////////////////////////////////
	// Name: Init
	//
	// Purpose: To initialize the Memory Manager and allocate any/all
	//			memory pools
	//
	// In:
	//		poolSizeInBytes - The size, in bytes, to allocate for
	//						  the internal pool of memory
	//
	// Out:
	//		none
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	void Init(unsigned int poolSizeInBytes);

	//////////////////////////////////////////////////////////////////
	// Name: Allocate
	//
	// Purpose: To find a chunk of free memory and allow access to it
	//
	// In:
	//		allocSize - The amount of memory, in bytes, to allocate
	//
	// Out:
	//		A char pointer pointing to the data that has been
	//		reserved
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	char* Allocate(unsigned int allocSize);

	//////////////////////////////////////////////////////////////////
	// Name: DeAllocate
	//
	// Purpose: To mark unused memory as free so that it can be reused
	//
	// In:
	//		data - A pointer to the data that you want to deallocate
	//
	// Out:
	//		none
	//
	// Original Author: Gant Briseno
	// Date Modified: 6/30/2011
	// Last Edited By: GB
	//////////////////////////////////////////////////////////////////
	void DeAllocate(char* data);
};
#endif